package top.mybatisx.mpquery.apt;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import top.mybatisx.mpquery.toolkit.StringCaseUtil;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Set;

@SupportedAnnotationTypes("com.baomidou.mybatisplus.annotation.TableName") // 只处理这个注解；
public class TableDefProcesser extends AbstractProcessor {

    // 整个类的模版
    private final static String model = "package @packageName;\n" +
            "import top.mybatisx.sql.core.table.QueryColumn;\n" +
            "import top.mybatisx.sql.core.table.TableDef;\n" +
            "public class @className extends TableDef {\n" +
            "public static final String table_name = \"@tableName\";\n" +
            "public static final QueryColumn STAR_ = new QueryColumn(\"*\", table_name);" +
            "public @className() {\n" +
            "super(table_name);\n" +
            "}\n" +
            "@columnList\n" +
            "}";
    private final static String fieldModel = "public static QueryColumn @COLUNMN_NAME = new QueryColumn(\"@COLUNMN_NAME\", table_name);\n";

    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        // Element操作类，用来处理Element的工具
        messager = processingEnv.getMessager();
        // print("初始化加载器.");
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        // 设置为能够支持最新版本
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // print("process 处理 annotations = " + annotations);
        for (TypeElement annotation : annotations) {
            Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
            // print("annotatedElements = " + annotatedElements);
            for (Element annotatedElement : annotatedElements) {
                if (annotatedElement instanceof TypeElement) {
                    TypeElement typeElement = (TypeElement) annotatedElement;
                    try {
                        rewriteCoder(typeElement, roundEnv);
                    } catch (Exception e) {
                        print("异常--->" + e.getCause() + e.getMessage());
                    }
                } else {
                    throw new RuntimeException("该注解只能用在类上");
                }
            }


        }

        return false;
    }

    void print(Object info) {
        messager.printMessage(Diagnostic.Kind.WARNING, info + "");
    }

    // 重写代码
    private void rewriteCoder(TypeElement annotation, RoundEnvironment roundEnv) throws IOException {
        // print(annotation);
        final String pcakgeClassName = annotation.getQualifiedName().toString();
        // final String pcakgeClassName = "sql";
        final String clazzName = annotation.getSimpleName().toString();

        // 1. 基础准备工作
        // final String packageName_ = pcakgeClassName.substring(0, pcakgeClassName.lastIndexOf(".")) + ".def";
        final String packageName_ = "sql.def";
        final String className_ = StringCaseUtil.camelToUpperCase(clazzName);
        TableName tableNameAnnotation = annotation.getAnnotation(TableName.class);
        final String tableName_ = tableNameAnnotation.value();

        // 2. 字段循环 所有属性的集合
        StringBuilder columnList = new StringBuilder();
        List<? extends Element> enclosedElements = annotation.getEnclosedElements();
        for (Element enclosedElement : enclosedElements) {
            if (enclosedElement instanceof VariableElement) {
                VariableElement variableElement = (VariableElement) enclosedElement;
                boolean isColumn = this.isColumn(variableElement);
                if (isColumn == false) continue;
                String columnName = this.getColumnName(variableElement);
                if (columnName == null) continue;
                String fieldColumn = fieldModel.replace("@COLUNMN_NAME", columnName);
                columnList.append(fieldColumn);
            }
        }


        // 3. 写入 内容
        String classContent = model;
        classContent = classContent.replace("@packageName", packageName_);
        classContent = classContent.replace("@className", className_);
        classContent = classContent.replace("@tableName", tableName_);

        classContent = classContent.replace("@columnList", columnList.toString());

        JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(className_);
        PrintWriter out = new PrintWriter(builderFile.openWriter());
        out.println(classContent);

        out.close();
    }

    private static boolean isColumn(VariableElement variableElement) {
        Set<Modifier> modifiers = variableElement.getModifiers();
        for (Modifier modifier : modifiers) {
            if ("static".equals(modifier.toString())) {
                return false;
            }
        }
        return true;
    }

    private String getColumnName(VariableElement variableElement) {
        TableId tableId = variableElement.getAnnotation(TableId.class);
        TableField tableField = variableElement.getAnnotation(TableField.class);
        if (tableId == null && tableField == null) {
            // 如果没注解,直接返回 小写_下划线
            return StringCaseUtil.camelToLowercase(variableElement.getSimpleName() + "");
        }
        if (tableField != null && tableField.exist()) {
            // 存在直接返回
            return tableField.value();
        }
        if (tableId != null) {
            // 存在直接返回
            return tableId.value();
        }
        return null;
    }


}
